In [ ]:
%%HTML
<style>
.container { width:100% }
</style>
The module Set
implements sets as
AVL trees.
The API provided by Set
offers the following functions and methods:
Set()
creates an empty set.S.isEmpty()
checks whether the set S
is empty.S.member(x)
checks whether x
is an element of the set S
.S.insert(x)
inserts x
into the set S
.
This does not return a new set but rather modifies the set S
.S.delete(x)
deletes x
from the set S
.
This does not return a new set but rather modifies the set S
.S.pop()
returns the smallest element of the set S
.
Furthermore, this element is removed from S
.
Since sets are implemented as ordered binary trees, the elements of a set need to be comparable, i.e. if x
and y
are inserted into a set, then the
expression x < y
must return a Boolean value and <
has to define
linear order.The module Set
can be used to implement a priority queue that supports the removal of elements.
In [ ]:
import Set
The function search
takes four arguments to solve a search problem:
start
is the start state of the search problem,goal
is the goal state, andnext_states
is a function with signature $\texttt{next_states}:Q \rightarrow 2^Q$, where $Q$ is the set of states.
For every state $s \in Q$, $\texttt{next_states}(s)$ is the set of states that can be reached from $s$ in one step.heuristic
is a function that takes two states as arguments. It
returns an estimate of the length of the shortest path between these
states.size
is the maximum number states that A$^*$ search is allowed
to explore.If successful, search
returns a path from start
to goal
that is a solution of the search problem
$$ \langle Q, \texttt{next_states}, \texttt{start}, \texttt{goal} \rangle. $$
The function search
implements A$^*$-IDA$^*$ search.
The main idea of A$^*$-IDA$^*$ is to run an $\mathrm{A}^*$ search from the node
start
until memory is more or less exhausted. Then, we start $\mathrm{IDA}^*$ from the node goal
node and search towards the node
start
until we find any of the nodes discovered by the $\mathrm{A}^*$ search
that had been started from the node start
node.
In [ ]:
def search(start, goal, next_states, heuristic, size):
Parent = { start:start }
Distance = { start: 0 }
estGoal = heuristic(start, goal)
Estimate = { start: estGoal }
Frontier = Set.Set()
Frontier.insert( (estGoal, start) )
while len(Distance) < size and not Frontier.isEmpty():
estimate, state = Frontier.pop()
if state == goal:
return path_to(state, Parent)
stateDist = Distance[state]
for ns in next_states(state):
oldEstimate = Estimate.get(ns, None)
newEstimate = stateDist + 1 + heuristic(ns, goal)
if oldEstimate == None or newEstimate < oldEstimate:
Distance[ns] = stateDist + 1
Estimate[ns] = newEstimate
Parent[ns] = state
Frontier.insert( (newEstimate, ns) )
if oldEstimate != None:
Frontier.delete( (oldEstimate, ns) )
Path = id_search(goal, start, next_states, heuristic, Distance)
return path_to(Path[-1], Parent) + Path[::-1][1:]
In [ ]:
def id_search(goal, start, next_states, heuristic, Distance):
limit = 0
while True:
print(f'limit = {limit}')
Path = dl_search([goal], start, next_states, limit, heuristic, Distance)
if isinstance(Path, list):
return Path
limit = Path
In [ ]:
def dl_search(Path, start, next_states, limit, heuristic, Distance):
state = Path[-1]
total = len(Path) - 1 + heuristic(state, start)
if total > limit:
return total
if state in Distance:
return Path
smallest = float('Inf')
for ns in next_states(state):
if ns not in Path:
result = dl_search( Path + [ns], start, next_states,
limit, heuristic, Distance
)
if isinstance(result, list):
return result
smallest = min(smallest, result)
return smallest
Given a state
and a parent dictionary Parent
, the function path_to
returns a path leading to the given state
.
In [ ]:
def path_to(state, Parent):
p = Parent[state]
if p == state:
return [state]
return path_to(p, Parent) + [state]
Lets draw the start state and animate the solution that has been found.
In [ ]:
%run Sliding-Puzzle.ipynb
In [ ]:
%%time
Path = search(start, goal, next_states, manhattan, 3000)
print(len(Path)-1)
In [ ]:
animation(Path)
In [ ]:
%%time
Path = search(start2, goal2, next_states, manhattan, 3000)
print(len(Path)-1)
In [ ]:
animation(Path)
In [ ]: